package com.example.first.thread;

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author LSQ
 * @Description 定义10个线程，锁只能被1个线程持有，只有持有锁的线程才能进入方法区进行计算
 * @date 2021/9/1 23:14
 * @Version 1.0
 */



public class LearnReentrantlock1 {

    private static final int CORE_POOL_SIZE = 30;
    private static final int MAX_POOL_SIZE = 50;
    // private static final int QUEUE_CAPACITY = Integer.MAX_VALUE;
    private static final int QUEUE_CAPACITY = 100;

    public static int count = 0;
    private static ReentrantLock lock = new ReentrantLock(true);

    public static void compute(int costTime, String currentThreadName) {

        System.out.printf("[ %s ] is computing... %n", currentThreadName);

        // 每个线程对count加1000次。
        for (int i = 0; i < 1000; i++) {
            count++;
            try {
                TimeUnit.MILLISECONDS.sleep(costTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }

    public static void main(String[] args) {

        ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE,
                0L, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(QUEUE_CAPACITY));


        for (int i = 0; i < 10; i++) {
            Random random = new Random();
            int taskExecuteTime = random.nextInt(10) + 1;
            // System.out.printf("running task %d%n", i);
            int taskNum = i;
            Runnable runnable = () -> {
                // 每次只有一个线程获取锁，如果上不了锁，就会自旋
                String currentThreadName = Thread.currentThread().getName();
                System.out.printf("[ %s ] get lock before! %n", currentThreadName);

                // 加锁的情况
                try {
                    lock.lock();
                    System.out.printf("[ %s ] get lock! %n", currentThreadName);
                    compute(taskExecuteTime, currentThreadName);

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }


                // 不加锁的情况
                // compute(taskExecuteTime, currentThreadName);


            };

            // System.out.printf("Task [ %d ] submit\n ", i);
            executorService.submit(runnable);

        }

        executorService.shutdown();

        while (true) {
            if (executorService.isTerminated()) {
                System.out.println("result " + count);
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("running...");
        }


    }


}

/*

结论：

1、每个线程只count++ 1次，看结果没有看出并发问题；
2、每个线程对count++ 1000次，没加锁的话会出现并发问题；
*/
